//全局变量 保存watch 
let W = null
//6观察者类 watcher
class Watcher {
  //每次使用差值语法 模板的 时候都需要的
  //Watcher实例化的时候接受两个参数,一个是key所在的对象 一个是key
  constructor(obj, key) {
    this.obj = obj
    this.key = key
    //当我要获取值的时候,把当前的watcher保存在全局变量上
    W = this
    //每一次实列化Watcher的时候就要得到值
    this.get()
    //在get中用完W,就把W给设置回去
    W = null
  }
  //每一次使用 都是为了得到一个值
  get() {
    //一旦这样拿值,就会直接进入当前key的响应式的getter函数中
    return this.obj[this.key]
  }
  //更新值
  update() {
    console.log(
      "gogogo,有人通知我了,我重新去请求数据是:" +
      this.get() +
      ",然后开始重新渲染视图!!!!"
    );
  }
}



// 5订阅器类 Dep
class Dep {
  constructor() {
    this.subs = []
  }
  depend(watcher) {
    //将收集到的watcher放入dep的数组中
    this.subs.push(watcher)
    console.log(
      "每次访问我的数据的时候,我就把watcher收集到dep.subs这个数组中",
      this.subs
    );
  }
  notify() {
    console.log("通知所有的watcher 重新加载新的数据");
    this.subs.forEach(watcher => {
      watcher.update()
    })
  }
}


// 4响应式核心函数
function defineReactive(_data, key, value) {
  //把value值再次交给observe方法,进行深层次的数据响应式(不需要判断,因为observe中有判断,如果是基本类型,则直接return,我们继续向下)
  observe(value);

  //每次对一个值进行响应式的时候,实例化一个Dep类
  const dep = new Dep()
  Object.defineProperty(_data, key, {
    get() {
      // console.log(`响应式取得值了 是${value}`);
      console.log("正在获取" + key + "的值", "收集所有依赖项watcher");
      //当这个数据被请求的时候,把观察者watcher收集起来到dep.subs中
      //我们可能不在模板解析的时候(也就是不是Watcher来要数据),我们需要做判断处理
      if (W) {
        dep.depend(W);
      }
      return value
    },
    set(newVal) {
      console.log("正在设置" + key + "的值", "通知所有的watcher进行更新");
      value = newVal;
      //当我的响应式数据被修改的时候,我要通知所有dep.subs里的watcher 进行更新
      dep.notify()
    }
  })
}


// 3封装发布者类
class Observer {

  constructor(_data) {
    this._data = _data

    //判断传来的数据是数组还是对象
    if (Array.isArray(_data)) {
      this.observeArr(_data)
    } else {
      this.walk(_data)
    }
  }

  observeArr(_data) {
    //当现在被操作的是数组的时候,我们不能直接使用defineProperty进行操作,但是我们要对数组内部的对象进行响应式操作
    _data.forEach(item => {
      //递归调用observe
      observe(item)
    })
  }
  walk(_data) {
    //如果是对象遍历对象的属性 对每一个属性进行响应式
    for (let key of Object.keys(_data)) {
      // 封装响应式核心函数
      defineReactive(_data, key, _data[key])
    }
  }

}


//2封装observe函数 对每一个属性进行响应式处理
function observe(_data) {

  if (typeof _data !== "object" || _data === null) return;

  new Observer(_data)


}

//1封装Vue构造函数
function Vue(options) {

  //数据代理
  this._data = options.data

  for (let key of Object.keys(this._data)) {

    Object.defineProperty(this, key, {
      get() {
        return this._data[key]
      },
      set(newVal) {
        this._data[key] = newVal
      }
    })
  }
  //拿到_data的数据开始进行响应式操作，我们首先把响应式操作的代码放在observe函数中
  observe(this._data)

}


let vm = new Vue({

  data: {
    count: 1,
    course: {
      type: "easy",
      name: "vue"
    }
  }

})

//两者用的同一个地址 改vm.data vm._data 的属性也有getter setter 方法
//  console.log(vm,"vm");

//  vm.count = 2

//  console.log(vm,"vm");

console.log(vm);
// function huoqu() {
//   console.log(vm.count,);
// }
// function shezhi() {
//   vm.count++;
//   // vm.count = 3;
// }
// huoqu()
// shezhi()

// --------------

function huoqu() {
  //模拟模板解析,每个组件都会实例化一个watcher 然后开始观察数据
  new Watcher(vm, "count");
}
function shezhi() {
  // vm.count++;
  vm.count = 3
}
huoqu();
shezhi()